package stream

import (
	"bufio"
	"bytes"
	"errors"
	"gitee.com/cooge/impush/message"
	"net"
	"strconv"
)

type MessageStream struct {
	Conn  net.Conn
	read_ *bufio.Reader
}

func NewMessageStream(conn net.Conn) *MessageStream {
	var ms MessageStream
	ms.Conn = conn
	ms.read_ = bufio.NewReader(conn)
	return &ms
}

func (this *MessageStream) read(len int) ([]byte, error) {
	data := make([]byte, len)
	var l = 0
	for l < len {
		n, err := this.read_.Read(data[l:])
		if err != nil {
			return nil, err
		}
		l += n
	}
	return data, nil
}

func (this *MessageStream) ReadLine() ([]byte, error) {
	buffer := bytes.Buffer{}
	for {
		data, is, err := this.read_.ReadLine()
		if err != nil {
			return data, err
		}

		if is {
			if len(data) > 0 {
				buffer.Write(data)
			}
		} else {
			buffer.Write(data)
			return buffer.Bytes(), nil
		}
	}
	return nil, nil
}

func (this *MessageStream) ReadMessage() (*message.Message, error) {

	var msg message.Message
	h := make(message.Head)
	for {
		rs, err := this.ReadLine()
		if err != nil {
			return nil, err
		}
		staff := bytes.IndexByte(rs, ':')
		if staff > -1 {
			h[string(rs[:staff])] = string(rs[staff+1:])
		} else {
			break
		}
	}
	length := h.Get(message.LENGTH)
	if len(length) > 0 {
		ll, err := strconv.Atoi(length)
		if err != nil {
			return nil, err
		}
		data, err := this.read(ll)
		if err == nil {
			msg.Body = data
		} else {
			return nil, err
		}
	} else {
		return nil, errors.New("READ MESSAGE FAULT")
	}
	msg.Heads = h
	data, err := this.read(4)
	if err == nil && bytes.Equal(data, endBytes) {
		return &msg, nil
	}
	return nil, errors.New("DATA FORMAT ERROR")
}

var endBytes = []byte{45, 13, 10, 45}
